#include <windows.h>
#include <string>
#include <stdio.h>
#include <stdlib.h>


typedef void _WOFILE;

std::wstring FullPathName( std::wstring fn ) {
int n;
for(n=fn.size(); n>0; n--) if(fn[n-1]!=L'\\' &&fn[n-1]!=L'/') break;
fn = fn.substr(0,n);
std::wstring tmp(1<<15,'\0');
n=GetFullPathNameW( &fn[0], 1<<15, &tmp[0], NULL);
tmp.resize(n);
if(memcmp(&tmp[0],L"\\\\?\\", 8)==0) return tmp; return L"\\\\?\\" + tmp; }


_WOFILE* _WOfopen( const std::wstring &fn , const std::wstring &mode) {
DWORD DesiredAccess, CreationDisposition;
do {
if(mode.find(L"a")!=std::string::npos ) { DesiredAccess=GENERIC_WRITE; CreationDisposition=  OPEN_ALWAYS; break; }
if(mode.find(L"w")!=std::string::npos ) { DesiredAccess=GENERIC_WRITE; CreationDisposition=CREATE_ALWAYS; break; }
if(mode.find(L"r")!=std::string::npos ) { DesiredAccess= GENERIC_READ; CreationDisposition=OPEN_EXISTING; break; }
return NULL;
}while(1);
if(mode.find(L"+")!=std::string::npos ) DesiredAccess |= GENERIC_READ|GENERIC_WRITE;
return CreateFileW( 
FullPathName(fn).c_str(), 
DesiredAccess, 
FILE_SHARE_READ, 
NULL, 
CreationDisposition, 
FILE_ATTRIBUTE_NORMAL, 
NULL ); }


int _WOfclose(_WOFILE *fp){ return CloseHandle(fp);   }



std::wstring char2wchar(const std::string &x) {
int m=x.size(); 
if(m<=0)return L"";
std::wstring y(m, L'\0');
m=MultiByteToWideChar(CP_ACP, 0, &x[0], m, &y[0], m); 
y.resize(m);  
return y; }



_WOFILE* _WOfopen( const std::string &fn , const std::string &mode) { return _WOfopen( char2wchar(fn), char2wchar(mode) ); }



int _WOfseek(_WOFILE *fp, long long offset, int origin) {
DWORD MoveMethod;
long DistanceToMove, DistanceToMoveHigh;
do {
if(origin==SEEK_CUR) { MoveMethod=FILE_CURRENT;  break; }
if(origin==SEEK_SET) { MoveMethod=FILE_BEGIN;  break; }
if(origin==SEEK_END) { MoveMethod=FILE_END;  break; }
return -1;
}while(1);
if( offset<=LONG_MAX && offset>=LONG_MIN ) {
DistanceToMove = SetFilePointer(fp, (long)offset, NULL, MoveMethod);
}
else {
DistanceToMove = offset & 0xFFFFFFFF;
DistanceToMoveHigh = (offset>>32) & 0xFFFFFFFF;
DistanceToMove = SetFilePointer(fp, DistanceToMove, &DistanceToMoveHigh, MoveMethod);
}
return (DistanceToMove==(long)0xFFFFFFFF);
}



long long _WOftell(_WOFILE *fp){
long DistanceToMove, DistanceToMoveHigh=0;
DistanceToMove = SetFilePointer( fp, 0, &DistanceToMoveHigh, FILE_CURRENT );
if(DistanceToMoveHigh==0) return DistanceToMove;
return ((long long)DistanceToMoveHigh<<32) | (long long)DistanceToMove;
}


size_t _WOfread(void *buf, size_t size, size_t n, _WOFILE *fp){
if(size==0 || n==0) return 0;
DWORD byte=0;
ReadFile(fp, buf, size*n, &byte, NULL);
return byte/size;
}


size_t _WOfwrite(void *buf, size_t size, size_t n, _WOFILE *fp){
if(size==0 || n==0) return 0;
DWORD byte=0;
WriteFile(fp, buf, size*n, &byte, NULL);
return byte/size;
}



int _WOfeof(_WOFILE *fp){
long long current = _WOftell(fp);
_WOfseek( fp, 0, SEEK_END);
long long end = _WOftell(fp);
_WOfseek( fp, current, SEEK_SET);
return current == end;
}

#define FILE _WOFILE
#define _wfopen _WOfopen
#define fopen _WOfopen
#define fseek _WOfseek
#define ftell _WOftell
#define fread _WOfread
#define fwrite _WOfwrite
#define fclose _WOfclose
#define feof _WOfeof